"""
装饰器 -python里面高阶函数的使用之一
"""
"""
装饰器模式应用:python装饰器
假如有一个方法A，你需要给方法加日志，打印方法的参数和返回值。并且修改原来方法名字
但是这个方法不是你创建的，调用的地方有很多。这时候java的处理办法
    新建一个方法B，这个方法B加上你需要的逻辑，然后方法B调用方法A就能实现
方法扩展:你不确定这个方法是什么，但是你就要日志那些逻辑。又想要这些方法的返回值。
    怎么处理-装饰器模式，
    1.使用高阶函数将函数作为被调用的参数传进去
    2.加上你想要的逻辑
    3.在里面定义一个新函数去调用你传入的函数
    4.拿到返回值并处理逻辑
    5.将你在里面定义的新函数作为返回值返回出去方便别人调用  
"""


def fun(a, b):
    return a + b


"""
需求在fun方法上中加上日志 开始结算和结束计算
代码实现:高阶函数返回值
"""


def fun_add():
    def add_fun(a, b):
        print("开始计算结果", "两个参数为", a, b)
        res = fun(a, b)
        print("结束计算结果，结果是", res)
        return res

    return add_fun


call_back = fun_add();
print(call_back(1, 2))
"""
需求扩展 如果不确定加日志的方法是fun,所有的方法都要求能加，怎么处理
解决方式是将需要添加日志的原方法作为参数传进来，然后在里面新建方法加日志并且调用该方法
再把新建方法作为返回值返回出去让别人调用 这样就能实现
注意:入参必须是方法，不能加括号 加了括号就是方法调用
    出参必须是里面定义的方法明一样不能加括号 这样才能被人调用
    调用的时候也是传方法 不能加括号调用 返回值再调用一次就能调用了
装饰器注解 在方法行加上@装饰方法就能快速完成装饰器
    多个装饰器的作用域，函数将会安装从内向外的顺序被装饰
"""


def fun_add_all(func):
    # 这里不确定调用函数的传参方式，就新建的参数要用可变参数来做参数
    # 试用装包拆包还进行拆分参数
    def fun_add(*num,**keyWords):
        print("方法开始，参数是", num, "方法名是", func.__name__)
        res = func(*num,**keyWords)
        print("方法结束，结果是", res)
        return res

    return fun_add


res_fun = fun_add_all(fun)
print(res_fun(3, 4))

# 装饰器注解：装饰器快速添加
@fun_add_all
def say_hello():
    print("你好，再见")

print(say_hello())